package ro.flashbite.game_engine.controller
{
	import flash.display.Sprite;
	import flash.utils.Dictionary;
	import flash.utils.getTimer;
	
	import ro.flashbite.errors.SingletonError;
	import ro.flashbite.game_engine.consts.MenuTypes;
	import ro.flashbite.game_engine.consts.StatesMenu;
	import ro.flashbite.game_engine.data.intefaces.IAppDataStorage;
	import ro.flashbite.game_engine.interfaces.IGameEngine;
	import ro.flashbite.game_engine.interfaces.IMenuToEngine;
	import ro.flashbite.game_engine.view.BaseMenu;
	import ro.flashbite.interfaces.ISleepWakeupDestroy;
	import ro.flashbite.loggers.ILogger;
	import ro.flashbite.loggers.LoggerFactory;
	
	public final class MenusManager implements ISleepWakeupDestroy, IMenuToEngine
	{
		private static var _instance:MenusManager;
		
		private var _appContainer:Sprite;
		
		private var _currentState:uint;
		
		private var _menuList:Array;
		private var _menuDict:Dictionary;
		
		private var _gameEngine:IGameEngine;
		
		private var _logger:ILogger;
		
		private var _currentMenu:BaseMenu;
		
		private var _lastMenuID:String
		
		// ================================================================================================================================
		// CONSTRUCTOR
		// ================================================================================================================================
		
		public function MenusManager(enforcer:SingletonEnforcer)
		{
			if (enforcer == null) throw new SingletonError();
			
			_logger = LoggerFactory.getLogger("MenusManager");
		}
		
		public static function getInstance():MenusManager
		{
			if (_instance == null) _instance = new MenusManager(new SingletonEnforcer());
			
			return _instance;
		}
		
		public function initialize(appContainer:Sprite, menuList:Array, gameEngine:IGameEngine):void
		{
			_currentState = StatesMenu.INACTIVE;
			
			_appContainer = appContainer;
			_gameEngine = gameEngine;
			
			_menuList = menuList;
			_menuDict = new Dictionary(true);
		}
		
		// ================================================================================================================================
		// ISleepWakeupDestroy
		// ================================================================================================================================
		
		public function sleep():void
		{
			if (_currentMenu) {
				_currentMenu.sleep();
			}
		}
		
		public function wakeup():void
		{
			if (_currentMenu) {
				_currentMenu.wakeup();
			}
		}
		
		public function destroy():void
		{
			_appContainer = null;
			_menuList = null;
			
			if (_menuDict) {
				var menuID:String,
					menu:BaseMenu;
				for (menuID in _menuDict) {
					menu = _menuDict[menuID];
					if (menu) menu.destroy();
					delete _menuDict[menuID];
				}
				_menuDict = null;
			}
			_gameEngine = null;
			
			if (_logger) {
				LoggerFactory.clearLogger(_logger.name);
				_logger = null;
			}
			_currentMenu = null;
			
			_instance = null;
		}

		// ================================================================================================================================
		// ILevelToEngine
		// ================================================================================================================================
		
		//callbacks in MenuManager
		public function openMenu(id:String, data:* = null, useBack:Boolean = false):void
		{
			closeCurrentMenu();
			
			//go open menu
			var menu:BaseMenu = _menuDict[id];
			if (menu) {
				_currentMenu = menu;
				_currentMenu.show(data, useBack);
				
				//save last menu to be accessed via back function
				if (useBack == false) _currentMenu.backMenuID = _lastMenuID;
				
				var menuType:uint = _currentMenu.TYPE;
				switch (menuType) {
					case MenuTypes.MAIN_MENU : 			 _currentState = StatesMenu.MAIN_MENU; break;
					case MenuTypes.SUB_MENU : 			 _currentState = StatesMenu.MAIN_SUB_MENU; break;
					case MenuTypes.PAUSE_MENU : 		 _currentState = StatesMenu.PAUSE_GAME_MENU; break;
					case MenuTypes.COMPLETE_LEVEL_MENU : _currentState = StatesMenu.COMPLETE_LEVEL_MENU; break;
					case MenuTypes.COMPLETE_GAME_MENU :  _currentState = StatesMenu.COMPLETE_GAME_MENU; break;
					case MenuTypes.GAME_OVER_MENU : 	 _currentState = StatesMenu.GAME_OVER_MENU; break;
					default : _logger.error("Menu type '" + menuType + "' unrecognized"); break;
				}
			} else {
				_logger.error("Couldn't open menu with id : "  + id);
			}
		}
		public function goBack():void
		{
			if (_lastMenuID) {
				//on back clicked, navigate to the 'parent' of this menu
				openMenu(_currentMenu.backMenuID, null, true);
			} else {
				_logger.error("Couldn't find last menu ID");
			}
		}
		
		//global callbacks to gameEngine
		public function loadLevel(id:String = null):void { _gameEngine.loadLevel(id); }
		
		public function resumeCurrentLevel():void { _gameEngine.resumeCurrentLevel(); }
		public function replayCurrentLevel():void { _gameEngine.replayCurrentLevel(); }
		public function closeCurrentLevel():void { _gameEngine.closeCurrentLevel(); }
		public function getCurrentLevelID():String { return _gameEngine.getCurrentLevelID(); }
		
		// IGameEngine functions
			//asset manager getting data
		public function getLevelAssetContent(id:String, type:String):Object { return _gameEngine.getLevelAssetContent(id, type); }
		public function getGlobalAssetContent(id:String, type:String):Object { return _gameEngine.getGlobalAssetContent(id, type); }
			//sound play/stop management
		public function playSound(ids:Array, closure:Function = null, loops:int = 1):Boolean { return _gameEngine.playSound(ids, closure, loops); }
		public function playSoundNoOverwrite(ids:Array, closure:Function = null, loops:int = 1):Boolean { return _gameEngine.playSoundNoOverwrite(ids, closure, loops); }
		public function stopSound(ids:Array):void { _gameEngine.stopSound(ids); }
		public function stopAllSounds():void { _gameEngine.stopAllSounds(); }
		public function getSoundLength(soundID:String):Number { return _gameEngine.getSoundLength(soundID); }
			//global saving data
		public function saveSharedData(id:String, data:Object, overwrite:Boolean = true):void { _gameEngine.saveSharedData(id, data, overwrite); }
		public function getSharedData(id:String):Object { return _gameEngine.getSharedData(id); }
			//global application storage
		public function getAppDataStorage():IAppDataStorage { return _gameEngine.getAppDataStorage(); }
		public function saveAppDataStorage():void { _gameEngine.saveAppDataStorage(); }
			//console callbacks
		public function addConsoleBinding(bindingID:String, bindingFunction:Function, bindingParam:Array = null, overwriteSame:Boolean = true):void { _gameEngine.addConsoleBinding(bindingID, bindingFunction, bindingParam, overwriteSame); }
		public function removeConsoleBinding(bindingID:String):void { _gameEngine.removeConsoleBinding(bindingID); }
		
		
		// ================================================================================================================================
		// PUBLIC
		// ================================================================================================================================
		
		public function initializeMenus():void
		{
			var time:uint = getTimer();
			
			for each (var lvlProp:Object in _menuList) {
				_menuDict[lvlProp.classID] = new lvlProp["className"](_appContainer, lvlProp.classID, this, lvlProp.type);
			}
			
			_logger.debug("Total time initializeMenus : " + uint(getTimer() - time) + " ms");
		}
		
		public function closeCurrentMenu():void
		{
			if (_currentMenu) {
				_lastMenuID = _currentMenu.ID;
				_currentMenu.hide();
				_currentMenu = null;
			} else _lastMenuID = null
			
			_currentState = StatesMenu.INACTIVE;
		}
		
		
		
		public function openPauseLevelMenu(id:String = null, data:* = null):void
		{
			if (id == null) {
				var pauseMenus:Vector.<BaseMenu> = getMenuByType(MenuTypes.PAUSE_MENU);
				if (pauseMenus.length) openMenu(pauseMenus[0].ID, data);
			} else {
				openMenu(id, data);
			}
		}
		
		public function openCompleteLevelMenu(id:String = null, data:* = null):void
		{
			if (id == null) {
				var completeMenus:Vector.<BaseMenu> = getMenuByType(MenuTypes.COMPLETE_LEVEL_MENU);
				if (completeMenus.length) openMenu(completeMenus[0].ID, data);
			} else {
				openMenu(id, data);
			}
		}
		
		public function openCompleteGameMenu(id:String = null, data:* = null):void
		{
			if (id == null) {
				var completeMenus:Vector.<BaseMenu> = getMenuByType(MenuTypes.COMPLETE_GAME_MENU);
				if (completeMenus.length) openMenu(completeMenus[0].ID, data);
			} else {
				openMenu(id, data);
			}
		}
		
		public function openGameOverLevelMenu(id:String = null, data:* = null):void
		{
			if (id == null) {
				var gameOverMenus:Vector.<BaseMenu> = getMenuByType(MenuTypes.GAME_OVER_MENU);
				if (gameOverMenus.length) openMenu(gameOverMenus[0].ID, data);
			} else {
				openMenu(id, data);
			}
		}
		
		public function openMainMenu():void
		{
			var mainMenus:Vector.<BaseMenu> = getMenuByType(MenuTypes.MAIN_MENU);
			if (mainMenus.length) openMenu(mainMenus[0].ID);
		}
		
		// ================================================================================================================================
		// PRIVATE
		// ================================================================================================================================
		
		private function getMenuByType(type:uint):Vector.<BaseMenu>
		{
			var menuID:String,
				menu:BaseMenu,
				menuVect:Vector.<BaseMenu> = new Vector.<BaseMenu>();
				
			for (menuID in _menuDict) {
				menu = _menuDict[menuID];
				if (menu.TYPE == type) menuVect.push(menu);
			}
			
			return menuVect;
		}
		
		private function getMenuByID(id:String):BaseMenu { return _menuDict[id]; }
		
		// ================================================================================================================================
		// GETTERS, SETTERS
		// ================================================================================================================================
		
		public function get currentState():uint { return _currentState; }
	}
}

class SingletonEnforcer {}